using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;



namespace LogParser
{
    class TF2LogParser
    {
        
        #region Private Member Variables

        private string _logFilePath;

        private List<string> _logLines;

        private List<Round> _rounds;

        private Collections.TeamList _teamList;
        private Collections.WeaponList _weaponList;

        private List<string> ChatLog;

        /// <summary>
        /// For holding global stats
        /// </summary>
        private Round _globalRound;

        #endregion

        #region Constructors

        public TF2LogParser()
        {

        }

        public TF2LogParser( string TF2LogFilePath )
        {
            this.LogFilePath = TF2LogFilePath;
        }

        #endregion

        #region Public Properties

        public string LogFilePath
        {
            set
            {
                _logFilePath = value;
                Initialize();
            }
            get
            {
                return _logFilePath;
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Do some setup and begin parsing
        /// </summary>
        private void Initialize()
        {
            _logLines = new List<string>();
            _rounds = new List<Round>();
            ChatLog = new List<string>();
            StringBuilder sb = new StringBuilder();


            string[] tempLines = System.IO.File.ReadAllLines( LogFilePath );

            string color = "DDDDDD";

            sb.AppendLine( "<table style=\"border: solid 1px black\">" );


            for ( int i = 0; i < tempLines.Length; i++ )
            {
                string workingLine = tempLines[ i ];

                // remove "L "
                if ( workingLine.StartsWith( "L " ) )
                    workingLine = workingLine.Substring( 2 );

                _logLines.Add( workingLine );




            }

            tempLines = null;


            sb.AppendLine( "</table>" );

            // Initialize our global round
            _globalRound = new Round();

            _teamList = new LogParser.Collections.TeamList();
            _weaponList = new LogParser.Collections.WeaponList();
        }

        #endregion

        #region Public Methods

        public bool Parse()
        {
            bool RoundStarted = false;

            Round CurrentRound = new Round();

            for ( int i = 0; i < _logLines.Count; i++ )
            {

                //foreach (string logLine in _logLines)
                //{

                string workingLine = _logLines[ i ];
                

                if ( workingLine.Contains( "\"Round_Setup_Begin\"" ) )
                {
                    RoundStarted = true;

                    DateTime eventTime = GetTime( ref workingLine );
                    CurrentRound.RoundStart = eventTime;

                    i++;
                    // Round has begun
                    // Parse the round events
                    // Advance i to the next record first
                    ParseRound( ref CurrentRound, ref i );

                    RoundStarted = false;


                    // Only add it if the round occurred
                    if ( CurrentRound.RoundDuration.Hours > 0 || CurrentRound.RoundDuration.Minutes > 0 || CurrentRound.RoundDuration.Seconds > 0 )
                    {
                        // Add the round to our collection for the entire match
                        _rounds.Add( CurrentRound );
                    }

                    CurrentRound = new Round();
                }
                else

                    // Collect information before any round begins
                    if ( RoundStarted == false )
                    {
                        // Get players and other information like chat

                        ParseEvent( ref CurrentRound, ref workingLine, RoundStarted );
                    }

                /*
                if ( workingLine.Contains( "say" ) )
                {
                    string tempLine = workingLine.Substring( workingLine.IndexOf( ":" ) + 1 );
                    tempLine = tempLine.Substring( tempLine.IndexOf( ":" ) + 1 );
                    tempLine = tempLine.Substring( tempLine.IndexOf( ":" ) + 1 );


                    for ( int k = 0; k < 2; k++ )
                    {
                        int beginIndex = 0;
                        int endIndex = 0;
                        beginIndex = tempLine.IndexOf( "<" );
                        endIndex = tempLine.IndexOf( ">" );

                        if ( tempLine.Contains( "guess we'll" ) )
                        {
                            ChatLog = new List<string>();
                        }
                        if ( beginIndex != endIndex )
                            tempLine = tempLine.Remove( beginIndex, endIndex - beginIndex + 1 );

                    }

                    tempLine = "<tr><td style=\"background-color: #" + color + "\">" + tempLine + "</td></tr>";

                    sb.AppendLine( tempLine );


                    if ( color == "DDDDDD" )
                        color = "FFFFFF";
                    else
                        color = "DDDDDD";


                }
*/


                //else if (RoundStarted)
                //{
                //    // Only log info if round is active

                //}
                //else if (logLine.Contains("World triggered \"Round_Start\""))
                //{
                //    // Round has begun
                //    RoundStarted = true;
                //    CurrentRound = new Round();

                //    CurrentRound.RoundStart = eventTime;

                //}
                //else if (RoundStarted == false)
                //{


                //}

            }

            return true;
        }



        private bool ParseRound( ref Round CurrentRound, ref int LogIndex )
        {
            int endIndex = _logLines.Count;

            // loop through
            for ( int i = LogIndex; i < endIndex; i++ )
            {
                string workingLine = _logLines[ i ];

                // restart of map without round ending
                if ( workingLine.Contains( "\"Mini_Round_Selected\"" ) )
                {
                    DateTime eventTime = GetTime( ref workingLine );
                    CurrentRound.RoundStart = eventTime;
                }

                //L 03/27/2008 - 18:39:57: World triggered "Mini_Round_Win" (winner "Blue") (round "round_1")
                //L 03/27/2008 - 18:39:57: World triggered "Mini_Round_Length" (seconds "545.39")
                // found the end of the round
                else if ( workingLine.Contains( "\"Mini_Round_Length\"" ) )
                {


                    DateTime eventTime = GetTime( ref workingLine );

                    // get the round end time
                    CurrentRound.RoundEnd = eventTime;

                    LogIndex = i;
                    i = endIndex + 1;
                }

                // Not a begin or end round event.
                else
                {
                    ParseEvent( ref CurrentRound, ref workingLine, true );
                }
            }


            return true;


        }

        /// <summary>
        /// Parses the event information and updates the appropriate records
        /// </summary>
        /// <param name="CurrentRound">Current round being processed</param>
        public void ParseEvent( ref Round CurrentRound, ref string workingLine, bool RoundStarted )
        {
            string PlayerName = String.Empty;
            string SteamID = string.Empty;
            string Team = string.Empty;

            DateTime eventTime = GetTime( ref workingLine );

            #region Example Log Lines

            // L 03/27/2008 - 18:07:21: "[Ars.rL] turb0z<11><STEAM_ID_PENDING><>" connected, address "67.53.13.88:27005"
            // L 03/27/2008 - 18:06:30: "[mg]Zimmerman<4><STEAM_0:1:3297696><Blue>" say "yes yes MOAR MOAR"

            #endregion

            // strip leading double quote
            // If the double quote exists, it means it was a player or console action
            if ( workingLine[ 0 ] == '"' )
            {
                workingLine = workingLine.Substring( 1 );


                // get the bit before the action
                string tempLine = workingLine.Substring( 0, workingLine.IndexOf( "\"" ) );


                // try to parse the user info out
                try
                {

                    // Likely to return in format....
                    // PlayerAttributes[0] = Team
                    // PlayerAttributes[1] = Steam ID
                    // PlayerAttributes[2] = Player ID in game
                    // PlayerAttributes[3] = Player Name
                    List<string> PlayerAttributes = ParsePlayer( tempLine );

                    PlayerName = PlayerAttributes[ 3 ];
                    SteamID = PlayerAttributes[ 1 ];
                    Team = PlayerAttributes[ 0 ];

                    Player tempPlayer = new Player();
                    tempPlayer.Name = PlayerName;
                    tempPlayer.SteamID = SteamID;

                    if ( Team == "" )
                    {
                        Team = "Unassigned";
                    }

                    tempPlayer.Team = _teamList.GetTeam( Team );  // Change this

                    if ( _globalRound.Players.ContainsKey( SteamID ) == false )
                        _globalRound.Players.Add( tempPlayer.SteamID, tempPlayer );

                    if ( RoundStarted == true )
                    {
                        if ( CurrentRound.Players.ContainsKey( tempPlayer.SteamID ) == false )
                            CurrentRound.Players.Add( tempPlayer.SteamID, tempPlayer );

                        ( (Player) CurrentRound.Players[ tempPlayer.SteamID ] ).IsDirty = false;
                    }

                }
                catch ( Exception ex )
                {

                }
            }

        }

        private List<string> ParsePlayer( string tempLine )
        {
            List<string> returnAttributes = new List<string>();

            int markerIndex = tempLine.LastIndexOf( "<" ) + 1;

            // Get the team
            returnAttributes.Add( tempLine.Substring( markerIndex, tempLine.Length - markerIndex - 1 ) );
            tempLine = tempLine.Substring( 0, markerIndex - 1 );

            // Get the steamid
            markerIndex = tempLine.LastIndexOf( "<" ) + 1;
            returnAttributes.Add( tempLine.Substring( markerIndex, tempLine.Length - markerIndex - 1 ) );
            tempLine = tempLine.Substring( 0, markerIndex - 1 );

            // Get the steamid
            markerIndex = tempLine.LastIndexOf( "<" ) + 1;
            returnAttributes.Add( tempLine.Substring( markerIndex, tempLine.Length - markerIndex - 1 ) );
            tempLine = tempLine.Substring( 0, markerIndex - 1 );

            // get the player name.  the remaining should be it
            returnAttributes.Add( tempLine );

            return returnAttributes;
        }

        // 03/27/2008 - 18:40:02: World triggered "Round_Setup_Begin"
        private DateTime GetTime( ref string workingLine )
        {
            //   /^L (\d{2})\/(\d{2})\/(\d{4}) - (\d{2}):(\d{2}):(\d{2}): (.+?)$/

            Regex dateTimePattern = new Regex( RegularExpressions.DATE_TIME );

            string[] splitSentence = dateTimePattern.Split( workingLine );

            //string temp = workingLine;
            //try
            //{
            //    int timeEndIndex = workingLine.IndexOf( ":" );
            //    string tempTime = workingLine.Substring( 0, timeEndIndex );


            //    int day, month, year, hour, min, sec;

            //    month = Convert.ToInt32( workingLine.Substring( 0, 2 ) );
            //    workingLine = workingLine.Substring( 3 );
            //    day = Convert.ToInt32( workingLine.Substring( 0, 2 ) );
            //    workingLine = workingLine.Substring( 3 );
            //    year = Convert.ToInt32( workingLine.Substring( 0, 4 ) );
            //    workingLine = workingLine.Substring( 7 );

            //    hour = Convert.ToInt32( workingLine.Substring( 0, 2 ) );
            //    workingLine = workingLine.Substring( 3 );
            //    min = Convert.ToInt32( workingLine.Substring( 0, 2 ) );
            //    workingLine = workingLine.Substring( 3 );
            //    sec = Convert.ToInt32( workingLine.Substring( 0, 2 ) );
            //    workingLine = workingLine.Substring( 4 );

            //    DateTime returnTime = new DateTime( year, month, day, hour, min, sec );


            //    return returnTime;
            //}
            //catch ( Exception ex )
            //{

            //}

            return DateTime.Now;
        }

        #endregion

    }
}
